/**
 * @file open_protocol_tiny.h
 * @author Zhenling Pan(ryan.pan@dji.com)
 * @brief
 * @version 0.1
 * @date 2022-01-28
 *
 * @copyright Copyright (c) 2022
 *
 */

#ifndef _OPEN_PROTOCOL_TINY_H_
#define _OPEN_PROTOCOL_TINY_H_

#include "linx_list.h"
#include "stdint.h"

#include "open_protocol_tiny_port.h"

#define OPEN_PROTOCOL_CRC16_INIT (0x4F19)
#define OPEN_PROTOCOL_CRC8_INIT (0x11)
#define OPEN_PROTOCOL_SOF (0xAA)

#define OPEN_PROTOCOL_UNPACK_TIMEOUT (1000)

#define OPEN_PROTOCOL_MAX_PACK_LENGTH (512)
#define OPEN_PROTOCOL_HEAP_MALLOC_MAX (2048)
#define OPEN_PROTOCOL_HEAP_MALLOC(NUM) heap_malloc(NUM)
#define OPEN_PROTOCOL_HEAP_FREE(MEM) heap_free(MEM)

#pragma pack(push, 1)

typedef struct {
  uint8_t sof;       /*!< 前导码 固定为0xAA  */
  uint16_t data_len; /*!< 数据段长度  */
  uint8_t crc8;      /*!< 对以上字节的CRC8校验  */
  uint16_t src_addr; /*!< 源地址  */
  uint16_t dst_addr; /*!< 目标地址  */
  union {
    struct {
      uint8_t is_ack : 1;   /*!< 本包是ACK包  */
      uint8_t need_ack : 1; /*!< 本包需要ACK */
      uint8_t res : 6;
    };
    uint8_t attr;
  };
  uint16_t seq_num; /*!< 序列号  */
  uint16_t cmd_id;  /*!< 命令号  */
  uint8_t data[];   /*!< data段  */
} open_protocol_header_t;

typedef union {
  struct {
    uint8_t sof;       /*!< 前导码 固定为0xAA  */
    uint16_t data_len; /*!< 数据段长度  */
    uint8_t crc8;      /*!< 对以上字节的CRC8校验  */
  } u;
  uint8_t data[4];
} open_protocol_pre_header_t;

typedef struct {
  list_t node;
  uint16_t len;
  open_protocol_header_t header;
} open_protocol_pack_node_t;

typedef struct {
  open_protocol_pack_node_t *recv_node;
  list_t recv_pack_list;
  open_protocol_pre_header_t pre_header;

  uint32_t time;
  uint16_t data_cnt;
  uint16_t err_num;
  uint16_t success_num;
  uint8_t step;
  uint8_t res; //确保结构体尺寸为4的倍数
} open_protocol_sniffer_t;

#pragma pack(pop)

void open_protocol_init(void);
void open_protocol_sniffer_init(open_protocol_sniffer_t *p);
void open_protocol_sniffer(uint8_t *buf, uint16_t len,
                           open_protocol_sniffer_t *p, uint32_t time);
open_protocol_pack_node_t *
open_protocol_get_pack_node(open_protocol_sniffer_t *p);
void open_protocol_free_pack_node(open_protocol_pack_node_t *node);

int open_ack_pack(uint8_t *buff, uint32_t buff_len,
                  open_protocol_header_t *req_header, uint32_t local_addr,
                  uint8_t *data, uint32_t data_len);

int open_normal_pack(uint8_t *buff, uint32_t buff_len, uint16_t cmd_id,
                     uint16_t src_addr, uint16_t dst_addr, uint8_t need_ack,
                     uint8_t *data, uint32_t data_len);

void open_protocol_forward_pack_node(open_protocol_pack_node_t *node);

#endif
